package com.tankgame.server;

import com.tankgame.models.BaseTank;
import com.tankgame.utils.UniqueTankVector;

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.*;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;
import java.util.Vector;

public class TankServer {
  public static final int TCP_PORT = 10086;
  public static final int UDP_PORT = 8888;
  public static int ID = 1000;
  public static String IP = "192.168.31.126";

  //坦克集合
  private UniqueTankVector allTanks = new UniqueTankVector();

  Vector<Client> clients = new Vector<>();

  public void start() {
    new Thread(new TCPThread()).start();
    new Thread(new UDPThread()).start();
  }

  public static void main(String[] args) {
    new TankServer().start();
  }

  private class Client {
    String ip;
    int udpPort;

    public Client(String ip, int udpPort) {
      this.ip = ip;
      this.udpPort = udpPort;
    }
  }


  //tcp线程
  private class TCPThread implements Runnable {
    @Override
    public void run() {
      try {
        //创建一个通道进行监听连接到TCP_PORT端口的连接
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.socket().bind(new InetSocketAddress(TankServer.IP, TCP_PORT));
        serverSocketChannel.configureBlocking(false);
        Selector selector = Selector.open();
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        while (true) {
          // 获取传入的连接
          selector.select();
          Set<SelectionKey> selectedKeys = selector.selectedKeys();
          Iterator<SelectionKey> iterator = selectedKeys.iterator();

          while (iterator.hasNext()) {
            SelectionKey key = iterator.next();
            iterator.remove();

            // 当判断到了有连接传入
            if (key.isAcceptable()) {
              ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
              SocketChannel socketChannel = ssc.accept();
              socketChannel.configureBlocking(false);
              String ip = socketChannel.socket().getInetAddress().getHostAddress();

              // 当客户端连接之后，将客户端的ip和ID传入到客户端
              // 临时将 socket channel 设置为阻塞模式
              socketChannel.configureBlocking(true);
              DataOutputStream dos = new DataOutputStream(socketChannel.socket().getOutputStream());
              dos.writeInt(ID);
              Client c = new Client(ip, ID++);
              clients.add(c);
              System.out.println("Client connected: " + ip + "：" + socketChannel.socket().getPort());
              // 将 socket channel 设置回非阻塞模式
              socketChannel.configureBlocking(false);

              socketChannel.close();
            }
          }
        }
      } catch (IOException e) {
        throw new RuntimeException(e);
      }
    }
  }


  //udp线程
  private class UDPThread implements Runnable {
    byte[] buf = new byte[1024];

    @Override
    public void run() {
      DatagramSocket datagramSocket = null;
      try {
        //创建udp socket
        datagramSocket = new DatagramSocket(UDP_PORT);
      } catch (SocketException e) {
        throw new RuntimeException(e);
      }
      System.out.println("UDP Thread started at port: " + UDP_PORT);
      while (datagramSocket != null) {
        //创建接收包
        DatagramPacket datagramPacket = new DatagramPacket(buf, buf.length);
        try {
          datagramSocket.receive(datagramPacket);

          // 将接收到的包中的坦克信息解析并加入到集合中
          ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(datagramPacket.getData(), 0, datagramPacket.getLength());
          DataInputStream dis = new DataInputStream(byteArrayInputStream);
          TankMsg tankMsg = new TankMsg();
          System.out.println("Received a packet from client: " + datagramPacket.getAddress() + " " + datagramPacket.getPort());
          BaseTank tank = tankMsg.parseTank(dis);
          allTanks.add(tank);
          System.out.println("坦克数量" + allTanks.size());

          tankMsg = new TankMsg(allTanks);
//          // 将包转发给所有客户端
          for (Client c : clients) {
            datagramPacket.setSocketAddress(new InetSocketAddress(c.ip, c.udpPort));
            tankMsg.sendAllTank(datagramSocket, c.ip, c.udpPort);
          }

          //解析移动包

        } catch (IOException e) {
          throw new RuntimeException(e);
        }
      }
    }
  }
}